classdef AnalogFilterDesign3 < handle
    
    properties     
        filterData; 
        
        freqUnits = 'Hz';
        handles;
        
        stagesList = {};
        cellList = {};
        selectedCells = [];
        stagesAxes = {};
        stagesButtons = {};
        stagesLimiters = {};
        circuitsIm = {};
        limitsIm = {};
        
        selectedStage = 1;
        stagesPlotsOrigin = 1;
        
        totalAttenuation;
    end
    
    properties (SetObservable, AbortSet)
        actualGUI = 1;
    end
    
    methods
        function this = AnalogFilterDesign3
            hfig = hgload('FilterDesignGUI3.fig');
            this.handles = guihandles(hfig);
            movegui(hfig, 'center');
            scrPos = get(this.handles.mainMenu, 'Position');
            scrPos(2) = scrPos(2) + 15;
            set(this.handles.mainMenu, 'Position', scrPos);
            
            bg_image = imread('Images/attenPassImg.png');
            set(this.handles.attenPassBut, 'Callback', @(src, event) attenPassSelect(this, src, event), 'CData', bg_image);
            bg_image = imread('Images/zoomImg.png');
            set(this.handles.zoomInBut, 'Callback', @(src, event) zoomInSelect(this, src, event), 'CData', bg_image);
            bg_image = imread('Images/panImg.png');
            set(this.handles.panBut, 'Callback', @(src, event) panSelect(this, src, event), 'CData', bg_image);
            bg_image = imread('Images/cursorImg.png');
            set(this.handles.cursorBut, 'Callback', @(src, event) cursorSelect(this, src, event), 'CData', bg_image);
            bg_image = imread('Images/gridImg.png');
            set(this.handles.gridToggle, 'Callback', @(src, event) gridSelect(this, src, event), 'CData', bg_image);
            set(this.handles.logLinToggle, 'Callback', @(src, event) logLinSelect(this, src, event));
            set(this.handles.hzRadToggle, 'Callback', @(src, event) hzRadSelect(this, src, event));
            
            set(this.handles.stagesSlider, 'Callback', @(src, event) sliderChange(this, src, event));
            set(this.handles.seeCircuitBut, 'Callback', @(src, event) seeCircuitSelect(this, src, event));
            set(this.handles.seeAttenuationBut, 'Callback', @(src, event) seeAttenuationSelect(this, src, event));
            
            set(this.handles.circuitList, 'Callback', @(src, event) circuitListSelect(this, src, event));
            set(this.handles.setValueBut, 'Callback', @(src, event) setValueSelect(this, src, event));
            set(this.handles.componentsList, 'Callback', @(src, event) componentsListSelect(this, src, event));
            
            set(this.handles.individualBut, 'Callback', @(src, event) individualPlotSelect(this, src, event));
            set(this.handles.acumulativeBut, 'Callback', @(src, event) acumulativePlotSelect(this, src, event));
            
            set(this.handles.stage1But, 'Callback', @(src, event) stageSelect(this, src, event));
            set(this.handles.stage2But, 'Callback', @(src, event) stageSelect(this, src, event));
            set(this.handles.stage3But, 'Callback', @(src, event) stageSelect(this, src, event));
            set(this.handles.stage4But, 'Callback', @(src, event) stageSelect(this, src, event));
            set(this.handles.stage5But, 'Callback', @(src, event) stageSelect(this, src, event));
            
            set(this.handles.leftStagesBut, 'Callback', @(src, event) leftStagesSelect(this, src, event));
            set(this.handles.rightStagesBut, 'Callback', @(src, event) rightStagesSelect(this, src, event));
            
            set(this.handles.publishFilterBut, 'Callback', @(src, event) publishFilterSelect(this, src, event));
            set(this.handles.backFilterBut, 'Callback', @(src, event) backFilterStage(this, src, event));
            
            this.limitsIm = cell(2,1);
            this.limitsIm{1} = imread('Stages Schematics/Vin.png');
            this.limitsIm{2} = imread('Stages Schematics/Vout.png');
            imcircuit1 = imread('Stages Schematics/TF.png');
            this.circuitsIm = {imcircuit1};
        end
        
        function createStages(this, numStages)
            this.stagesLimiters = cell(2, 1);
            this.stagesLimiters{1} = axes('Parent', this.handles.stagesPanel, 'Units', 'Pixels', 'Position', [5, 100, 43, 336]);
            this.stagesLimiters{2} = axes('Parent', this.handles.stagesPanel, 'Units', 'Pixels', 'Position', [5 + 43 + 478*numStages, 100, 43, 336]);
            imagesc(this.limitsIm{1}, 'Parent', this.stagesLimiters{1});
            imagesc(this.limitsIm{2}, 'Parent', this.stagesLimiters{2});
            removeAxis(this.stagesLimiters{1});
            removeAxis(this.stagesLimiters{2});
            set(this.stagesLimiters{1}, 'Visible', 'Off');
            set(this.stagesLimiters{2}, 'Visible', 'Off');
            
            for stageInd = 1:numStages
                this.stagesAxes{stageInd} = axes('Parent', this.handles.stagesPanel, 'Units', 'Pixels', 'Position', [5 + 43 + 478*(stageInd-1), 100, 478, 336]);
                this.stagesButtons{stageInd} = uicontrol('Parent', this.handles.stagesPanel, 'Style', 'togglebutton', 'Units', 'Pixels', 'Position', [5 + 43 + 139 + 478*(stageInd-1), 45, 200, 40], 'Fontsize', 12, 'String', strcat({'Stage '}, num2str(stageInd)));
                set(this.stagesButtons{stageInd}, 'Callback', @(src, event) stageSelect(this, src, event));
                if stageInd > 2
                   set(this.stagesButtons{stageInd}, 'Visible', 'Off');
                end
                imagesc(this.circuitsIm{1},'Parent', this.stagesAxes{stageInd});
                removeAxis(this.stagesAxes{stageInd});
                set(this.stagesAxes{stageInd}, 'Visible', 'Off');
            end
            
            if numStages > 1
                set(this.handles.stagesSlider, 'Visible', 'On', 'SliderStep', [0.25/numStages, 2/numStages]);
            else
                set(this.handles.stagesSlider, 'Visible', 'Off');
            end
            set(this.handles.circuitList, 'Value', 1);
            this.cellList = cell(length(this.stagesList), 2);
            this.createCellList();
            this.refreshComponentsList();
            this.refreshSensivities();
            this.selectedStage = 1;
            this.stagesPlotsOrigin = 1;
        end
        
        function deleteElements(this)
            for k = 1:length(this.stagesButtons)
                delete(this.stagesButtons{k});
            end
            this.stagesButtons = {};
            for k = 1:length(this.stagesLimiters)
                delete(this.stagesLimiters{k});
            end
            this.stagesLimiters = {};
            for k = 1:length(this.stagesAxes)
                delete(this.stagesAxes{k});
            end
            this.stagesAxes = {};
            for k = 1:length(this.stagesList)
                delete(this.stagesList{k});
            end
            this.stagesList = {};
        end
        
        function setStagesData(this, filterData, stagesList, totalAttenuation)
            this.stagesList = {};

            this.stagesList = stagesList;
            
            this.filterData = filterData;

            this.createStages(length(stagesList));
            
            this.totalAttenuation = totalAttenuation;
            
            set(this.handles.seeCircuitBut, 'Value', 1);
            set(this.handles.seeAttenuationBut, 'Value', 0);
            this.seeCircuitSelect(this.handles.seeCircuitBut, 0);
            this.refreshCircuitsList();
            this.refreshStagesBar();
        end
        
        function this = attenPassSelect(this, ~, ~)
            this.doAttenuationPlot();
        end
        
        function this = zoomInSelect(this, ~, ~)
            zoom;
        end
        
        function this = panSelect(this, ~, ~)
            pan;
        end
        
        function this = cursorSelect(this, ~, ~)
            datacursormode;
        end
        
        function this = gridSelect(this, src, ~)
            if get(src, 'Value')
                grid(this.handles.attenuationPlot, 'On')
            else
                grid(this.handles.attenuationPlot, 'Off')
            end
        end
        
        function this = logLinSelect(this, src, ~)
            if get(src, 'Value')
                set(this.handles.attenuationPlot,'XScale','lin');
            else
                set(this.handles.attenuationPlot,'XScale','log');
            end
        end
        
        function this = hzRadSelect(this, src, ~)
            if get(src, 'Value')
                this.freqUnits = 'rad/s';
            else
                this.freqUnits = 'Hz';
            end
            
            this.doAttenuationPlot();
        end
        
        function visible(this, value)
            if value == 3
                set(this.handles.mainMenu, 'Visible', 'On');
            else
                set(this.handles.mainMenu, 'Visible', 'Off');
            end
        end
        
        function refreshAxes(this, stagen)
            if get(this.handles.seeCircuitBut, 'Value')
                set(this.stagesAxes{stagen}, 'Visible', 'On');
                imageC = imread(this.cellList{stagen, 1}{this.selectedCells(stagen)}.ImagePath);
                cla(this.stagesAxes{stagen});
                imagesc(imageC, 'Parent', this.stagesAxes{stagen});
                removeAxis(this.stagesAxes{stagen});
                set(this.stagesAxes{stagen}, 'Visible', 'Off');
            end
        end
        
        function refreshAllAxes(this)
            if get(this.handles.seeCircuitBut, 'Value')
                numStages = length(this.stagesList);
                for i = 1:numStages
                    this.refreshAxes(i);
                    pPanelLen = get(this.handles.stagesPanel, 'Position');
                    buttonLen = get(this.stagesButtons{i}, 'Position');
                    if (buttonLen(1) > 0) && ((buttonLen(1)+buttonLen(3)) < pPanelLen(3))
                        set(this.stagesButtons{i}, 'Visible', 'On', 'Callback', @(src, event) stageSelect(this, src, event));
                    else
                        set(this.stagesButtons{i}, 'Visible', 'Off', 'Callback', @(src, event) stageSelect(this, src, event));
                    end
                end
                set(this.stagesLimiters{1}, 'Visible', 'On');
                set(this.stagesLimiters{2}, 'Visible', 'On');
                imagesc(this.limitsIm{1}, 'Parent', this.stagesLimiters{1});
                imagesc(this.limitsIm{2}, 'Parent', this.stagesLimiters{2});
                removeAxis(this.stagesLimiters{1});
                removeAxis(this.stagesLimiters{2});
                set(this.stagesLimiters{1}, 'Visible', 'Off');
                set(this.stagesLimiters{2}, 'Visible', 'Off');
            end
        end
        
        function cleanAllAxes(this)
            numStages = length(this.stagesList);
            for i = 1:numStages
                cla(this.stagesAxes{i});
                set(this.stagesButtons{i}, 'Visible', 'Off');
            end
            cla(this.stagesLimiters{1});
            cla(this.stagesLimiters{2});
        end
        
        function this = sliderChange(this, src, ~)
            sliderVal = get(src, 'Value');
            axesLen = get(this.stagesAxes{1}, 'Position');
            pPanelLen = get(this.handles.stagesPanel, 'Position');
            limitersLen = get(this.stagesLimiters{1}, 'Position');
            for i = 1:length(this.stagesList)
                set(this.stagesAxes{i}, 'Position', [5 + limitersLen(3) + axesLen(3)*(i-1) - ((length(this.stagesList)-2)*axesLen(3) + limitersLen(3)+10)*sliderVal, axesLen(2), axesLen(3), axesLen(4)])
                set(this.stagesButtons{i}, 'Visible', 'Off');
                set(this.stagesButtons{i}, 'Position', [5 + limitersLen(3) + 139 + axesLen(3)*(i-1) - ((length(this.stagesList)-2)*axesLen(3) + limitersLen(3)+10)*sliderVal, axesLen(2) - 55, 200, 40]);
                buttonLen = get(this.stagesButtons{i}, 'Position');
                if (buttonLen(1) > 0) && ((buttonLen(1)+buttonLen(3)) < pPanelLen(3))
                    set(this.stagesButtons{i}, 'Visible', 'On');
                else
                    set(this.stagesButtons{i}, 'Visible', 'Off');
                end
            end
            set(this.stagesLimiters{1}, 'Position', [5 - ((length(this.stagesList)-2)*axesLen(3) + limitersLen(3)+10)*sliderVal, axesLen(2), limitersLen(3), limitersLen(4)])
            set(this.stagesLimiters{2}, 'Position', [5 + limitersLen(3) + axesLen(3)*length(this.stagesList) - ((length(this.stagesList)-2)*axesLen(3) + limitersLen(3)+10)*sliderVal, axesLen(2), limitersLen(3), limitersLen(4)])
        end
        
        function this = seeCircuitSelect(this, src, ~)
            numStages = length(this.stagesList);
            set(this.handles.axesControlPanel, 'Visible', 'Off');
            set(this.handles.axesViewPanel, 'Visible', 'Off');
            set(this.handles.attenuationPlot, 'Visible', 'Off');
            cla(this.handles.attenuationPlot);
            if get(src, 'Value')
                this.refreshAllAxes();
                if numStages > 1
                    set(this.handles.stagesSlider, 'Visible', 'On', 'SliderStep', [0.25/numStages, 2/numStages]);
                else
                    set(this.handles.stagesSlider, 'Visible', 'Off');
                end
            end
            
        end
        
        function this = seeAttenuationSelect(this, src, ~)
            if get(src, 'Value')
                this.cleanAllAxes();
                set(this.handles.stagesSlider, 'Visible', 'Off');
            end
            set(this.handles.axesControlPanel, 'Visible', 'On');
            set(this.handles.axesViewPanel, 'Visible', 'On');
            set(this.handles.attenuationPlot, 'Visible', 'On');
            x = 1:1000;
            plot(this.handles.attenuationPlot, x, x/10, 'b', x, x/10.+(sin(x).*rand(1000,1)'*4), 'r');
            % Bring to front Attenuation Plot
            h = get(this.handles.stagesPanel,'Children');
            attPlotInd = findobj(this.handles.attenuationPlot);
            h2 = [h(h==attPlotInd(1))' h(h~=attPlotInd(1))']';
            set(this.handles.stagesPanel,'Children', h2);
            this.doAttenuationPlot();
        end
        
        function doAttenuationPlot(this)
            cla(this.handles.attenuationPlot);
            if strcmp(this.freqUnits, 'Hz')
                freq = this.stagesList{this.selectedStage}.freq;
            else
                freq = this.stagesList{this.selectedStage}.freq * (2*pi);
            end
            a = find(freq > freq(1)*10, 1, 'first');
            b = find(freq > freq(end)/10, 1,'first');
            if get(this.handles.individualBut, 'Value')
                semilogx(this.handles.attenuationPlot, freq, this.stagesList{this.selectedStage}.attenuation, 'b');
                yMin = min(this.stagesList{this.selectedStage}.attenuation(a:b));
                yMax = max(this.stagesList{this.selectedStage}.attenuation(a:b));
                title(this.handles.attenuationPlot, strcat({'Attenuation Stage '}, num2str(this.selectedStage)), 'FontSize', 11);
            else
                semilogx(this.handles.attenuationPlot, freq, this.totalAttenuation, 'b');
                yMin = min(this.totalAttenuation(a:b));
                yMax = max(this.totalAttenuation(a:b));
                title(this.handles.attenuationPlot, 'Acumulative Attenuation', 'FontSize', 11);
                if get(this.handles.attenPassBut, 'Value')
                    drawAttenPass(this.filterData, this.handles.attenuationPlot, this.freqUnits);
                end
            end
            xlim(this.handles.attenuationPlot, [freq(1)*10, freq(end)/10]);
            if yMin ~= yMax
                ylim(this.handles.attenuationPlot, [yMin yMax]);
            else
                ylim(this.handles.attenuationPlot, [yMin-20 yMax+20]);
            end
            xlabel(this.handles.attenuationPlot, strcat('Frequency [', this.freqUnits, ']'), 'FontSize', 11);
            ylabel(this.handles.attenuationPlot, 'Attenuation [dB]', 'FontSize', 11);
            this.gridSelect(this.handles.gridToggle, 0);
        end
        
        function this = individualPlotSelect(this, ~, ~)
            this.doAttenuationPlot();
        end
        
        function this = acumulativePlotSelect(this, ~, ~)
            this.doAttenuationPlot();
        end
        
        function this = stageSelect(this, src, ~)
            buttonStr = get(src, 'String');
            this.selectedStage = str2double(buttonStr{1}(7:end));
            set(this.handles.componentsList, 'Value', 1);
            set(this.handles.sensivitiesList, 'Value', 1);
            set(this.handles.circuitList, 'Value', this.selectedCells(this.selectedStage));
            set(this.handles.configPanel, 'Title', strcat({'Config Panel Stage '}, num2str(this.selectedStage)));
            if get(this.handles.seeCircuitBut, 'Value')
                if this.selectedStage == 1
                    set(this.handles.stagesSlider, 'Value', 0);
                elseif this.selectedStage == length(this.stagesList)
                    set(this.handles.stagesSlider, 'Value', 1);
                else
                    axesLen = get(this.stagesAxes{1}, 'Position');
                    pPanelLen = get(this.handles.stagesPanel, 'Position');
                    limitersLen = get(this.stagesLimiters{1}, 'Position');
                    sliderVal = (5+limitersLen(3)+axesLen(3)*(this.selectedStage-1/2)-pPanelLen(3)/2)/((length(this.stagesList)-2)*axesLen(3)+limitersLen(3)+10);
                    set(this.handles.stagesSlider, 'Value', sliderVal);
                end
                for k = 1:length(this.stagesButtons)
                    if k == this.selectedStage
                        set(this.stagesButtons{k}, 'Value', 1);
                    else
                        set(this.stagesButtons{k}, 'Value', 0);
                    end
                end
                this.sliderChange(this.handles.stagesSlider, 0);
            else
                this.doAttenuationPlot();
            end
            this.refreshCircuitsList();
            this.refreshStagesBar();
            this.refreshComponentsList();
            this.refreshSensivities();
        end
        
        function this = leftStagesSelect(this, ~, ~)
            this.stagesPlotsOrigin = this.stagesPlotsOrigin - 1;
            this.refreshStagesBar();
        end
        
        function this = rightStagesSelect(this, ~, ~)
            this.stagesPlotsOrigin = this.stagesPlotsOrigin + 1;
            this.refreshStagesBar();
        end
        
        function publishFilterSelect(this, ~, ~)
            finishCells = cell(length(this.stagesList), 1);
            for k = 1:length(this.stagesList)
                finishCells{k} = this.cellList{k, 1}{this.selectedCells(k)};
            end
            Export(this.filterData, finishCells, this.stagesList);
        end
        
        function backFilterStage(this, ~, ~)
            this.deleteElements();
            this.actualGUI = 2 + rand(1,1)/2;
        end
        
        function refreshStagesBar(this)
            this.cleanStagesBar();
            if ~isempty(this.stagesList)
                if length(this.stagesList) <= 5
                    numPlots = length(this.stagesList);
                    this.stagesPlotsOrigin = 1;
                else
                    numPlots = 5;
                    if this.stagesPlotsOrigin > 1
                        set(this.handles.leftStagesBut, 'Enable', 'On');
                    end
                    if (length(this.stagesList) - this.stagesPlotsOrigin) >= 5
                        set(this.handles.rightStagesBut, 'Enable', 'On');
                    end
                end

                for i = 1:numPlots
                    switch i
                        case 1
                            hP = this.handles.axes1;
                            but = this.handles.stage1But;
                        case 2
                            hP = this.handles.axes2;
                            but = this.handles.stage2But;
                        case 3
                            hP = this.handles.axes3;
                            but = this.handles.stage3But;
                        case 4
                            hP = this.handles.axes4;
                            but = this.handles.stage4But;
                        case 5
                            hP = this.handles.axes5;
                            but = this.handles.stage5But;
                    end
                    
                    semilogx(hP, this.stagesList{i+this.stagesPlotsOrigin-1}.freq, this.stagesList{i+this.stagesPlotsOrigin-1}.attenuation);
                    xlim(hP, [this.stagesList{i+this.stagesPlotsOrigin-1}.freq(1)*10, this.stagesList{i+this.stagesPlotsOrigin-1}.freq(end)/10]);
                    removeAxis(hP);
                    set(but, 'String', strcat({'Stage '}, num2str(i+this.stagesPlotsOrigin-1)), 'Visible', 'On');
                    if this.selectedStage == (i+this.stagesPlotsOrigin-1)
                        set(but, 'Value', 1)
                    else
                        set(but, 'Value', 0)
                    end
                    yMin = min(this.stagesList{i+this.stagesPlotsOrigin-1}.attenuation);
                    yMax = max(this.stagesList{i+this.stagesPlotsOrigin-1}.attenuation);
                    if abs(yMin - yMax) < 1e-12
                        ylim(hP, [yMin-20, yMin+20]);
                    end
                    this.gridSelect(this.handles.gridToggle, 0);
                    this.gridSelect(this.handles.gridToggle, 0);
                end
            end
        end
        
        function cleanStagesBar(this)
            cla(this.handles.axes1);
            cla(this.handles.axes2);
            cla(this.handles.axes3);
            cla(this.handles.axes4);
            cla(this.handles.axes5);
            set(this.handles.axes1, 'Visible', 'Off');
            set(this.handles.axes2, 'Visible', 'Off');
            set(this.handles.axes3, 'Visible', 'Off');
            set(this.handles.axes4, 'Visible', 'Off');
            set(this.handles.axes5, 'Visible', 'Off');
            set(this.handles.stage1But, 'Visible', 'Off', 'Value', 0);
            set(this.handles.stage2But, 'Visible', 'Off', 'Value', 0);
            set(this.handles.stage3But, 'Visible', 'Off', 'Value', 0);
            set(this.handles.stage4But, 'Visible', 'Off', 'Value', 0);
            set(this.handles.stage5But, 'Visible', 'Off', 'Value', 0);
            set(this.handles.leftStagesBut, 'Enable', 'Off');
            set(this.handles.rightStagesBut, 'Enable', 'Off');
        end

        function refreshCircuitsList(this)
            strList = [];
            for k = 1:length(this.cellList{this.selectedStage,1})
                str = this.cellList{this.selectedStage,1}{k}.Name;
                strList = [strList; {str}];
            end
            set(this.handles.circuitList, 'String', strList);
        end
        
        function this = circuitListSelect(this, src, event)
            cellListVal = get(src, 'Value');
            this.selectedCells(this.selectedStage) = cellListVal;
            this.refreshComponentsList();
            this.refreshSensivities();
            this.refreshAxes(this.selectedStage);
        end
        
        function this = createCellList(this, ~, ~)
            for m = 1:1
                for k = 1:length(this.stagesList)
                    switch this.stagesList{k}.FilterType
                        case 'HighPassFirstOrd'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = DiffInv(this.stagesList{k}.poles, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = DiffNoInv(this.stagesList{k}.poles, this.stagesList{k}.Gi);

                        case 'LowPassFirstOrd'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = IntInv(this.stagesList{k}.poles, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = IntegNoInv(this.stagesList{k}.poles, this.stagesList{k}.Gi);

                        case 'LowPassSecondOrd'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = LowPassSK(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = LowPassKHN(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);

                        case 'HighPassSecondOrd'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = HighPassSK(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = HighPassKHN(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);

                        case 'BandPass'
                            this.cellList{k,m} = cell(3,1);
                            this.cellList{k,m}{1} = BandPassRauch(this.stagesList{k}.poles, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = BandPassSK(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                            this.cellList{k,m}{3} = BandPassKHN(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);

                        case 'LowPassNotch'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = LowpassNotchSGM(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = TowFleischer(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);

                        case 'HighPassNotch'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = HighpassSGM(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = TowFleischer(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);

                        case 'BandReject'
                            this.cellList{k,m} = cell(1,1);
                            this.cellList{k,m}{1} = BandStopKHN(this.stagesList{k}.poles, this.stagesList{k}.zeros, this.stagesList{k}.Gi);
                        
                        case 'GainStage'
                            this.cellList{k,m} = cell(2,1);
                            this.cellList{k,m}{1} = InvGain(this.stagesList{k}.Gi);
                            this.cellList{k,m}{2} = NoInvGain(this.stagesList{k}.Gi);
                    end
                    for l = 1:length(this.cellList{k,m}) % Delete non-valid cells
                        if this.cellList{k,m}{l}.error
                            this.cellList{k,m}{l} = [];
                        end
                    end
                    this.cellList{k,m} = this.cellList{k,m}(~cellfun('isempty',this.cellList{k,m}));
                    if isempty(this.selectedStage)
                        disp('No hay celdas disponibles')
                    end
                end
            end
            this.defaultCells();
        end
        
        function defaultCells(this)
            for k = 1:length(this.stagesList)
                this.selectedCells(k) = 1;
                this.refreshAxes(k);
            end
            
        end
        
        function this = componentsListSelect(this, src, event)
            listVal = get(src, 'Value');
            resLen = length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists);
            if listVal <= resLen
                compType = 'R';
                compNum = num2str(listVal);
                compUnit = '&Omega;';
                set(this.handles.compValue, 'String', num2compstr(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists(listVal), 1));
            else
                compType = 'C';
                compNum = num2str(listVal - resLen);
                compUnit = 'F';
                set(this.handles.compValue, 'String', num2compstr(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Caps(listVal - resLen), 1));
            end
            set(this.handles.compName, 'String', strcat({'<HTML><span>'}, compType, {'<sub>'}, compNum, {'</sub>'}, {'</span></HTML>'}));
            set(this.handles.compUnit, 'String', strcat({'<HTML><span>'}, compUnit, {'</span></HTML>'}));
        end
        
        function this = setValueSelect(this, src, event)
            value = str2compnum(get(this.handles.compValue, 'String'));
            listVal = get(this.handles.componentsList, 'Value');
            resLen = length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists);
            if listVal <= resLen
                compType = 'R';
            else
                compType = 'C';
            end
            if (compType == 'R')
                if isnan(value) || (value < 10) || (value > 10e6)
                    errordlg('Error: The component value must be a numeric value between 10 and 10M', 'Inconsistent error');
                end
            else
                if isnan(value) || (value < 100e-12) || (value > 1000e-6)
                    errordlg('Error: The component value must be a numeric value between 100p and 1000u', 'Inconsistent error');
                end
            end
            this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.componentChange(listVal, value);
            this.refreshComponentsList();
            this.refreshSensivities();
            return;
        end
        
        function refreshComponentsList(this)
            strTotal = [];
            for k = 1:length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists)
                type = 'R';
                value = this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists(k);
                ntype = num2str(k);
                oriVal = num2compstr(value, 1);
                comInfo = comercialValue(type, value);
                utype = '&Omega;';
                comVal = [comInfo.R1, comInfo.R2];
                if comInfo.cantComp > 1
                    uCom = comInfo.conection;
                    comStr = strcat('(', num2compstr(comVal(1), 1), uCom, num2compstr(comVal(2), 1), ')');
                else
                    comStr = num2compstr(comVal(1), 1);
                end
                if comInfo.error < 0.099
                    comErr = num2str(round(comInfo.error * 10000)/100);
                else
                    comErr = '>10';
                end
                if (value>= 10) && (value<=10e6)
                    bgcolor = 'FFFFFF';
                else
                    bgcolor = 'FF0000';
                end
                str = strcat({'<HTML><table border="1" style="width:177px" bgcolor="#'}, bgcolor,{'" color="black"><tr><td style="width:14%;text-align:center;font-size:9px">'}, type, {'<sub>'}, ntype, {'</sub></td><td style="width:27%;text-align:center;font-size:9px">'}, oriVal, utype, {'</td><td style="width:59%;text-align:center;font-size:9px">'}, comStr, utype,{', '}, comErr, {'%</td></tr></HTML>'});
                strTotal = [strTotal; str];
            end
            for m = 1:length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Caps)
                type = 'C';
                value = this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Caps(m);
                ntype = num2str(m);
                oriVal = num2compstr(value, 1);
                comInfo = comercialValue(type, value);
                utype = 'F';
                comVal = [comInfo.C1, comInfo.C2];
                if comInfo.cantComp > 1
                    uCom = comInfo.conection;
                    comStr = strcat('(', num2compstr(comVal(1), 1), uCom, num2compstr(comVal(2), 1), ')');
                else
                    comStr = num2compstr(comVal(1), 1);
                end
                if comInfo.error < 0.099
                    comErr = num2str(round(comInfo.error * 10000)/100);
                else
                    comErr = '>10';
                end
                if (value>= 100e-12) && (value<=1000e-6)
                    bgcolor = 'FFFFFF';
                else
                    bgcolor = 'FF0000';
                end
                str = strcat({'<HTML><table border="1" style="width:177px" bgcolor="#'}, bgcolor, {'" color="black"><tr><td style="width:14%;text-align:center;font-size:9px">'}, type, {'<sub>'}, ntype, {'</sub></td><td style="width:27%;text-align:center;font-size:9px">'}, oriVal, utype, {'</td><td style="width:59%;text-align:center;font-size:9px">'}, comStr, utype,{', '}, comErr, {'%</td></tr></HTML>'});
                strTotal = [strTotal; str];
            end
            set(this.handles.componentsList, 'String', strTotal);
        end
        
        function refreshSensivities(this)
            strTotal = [];
            for m = 1:4
                switch m
                    case 1
                        suptype = '&omega;p';
                        supSelect = 'Senswp';
                    case 2
                        suptype = '&omega;z';
                        supSelect = 'Senswz';
                    case 3
                        suptype = 'Q';
                        supSelect = 'SensQ';
                    case 4
                        suptype = 'G';
                        supSelect = 'SensG';
                end
                if ~isempty(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.(supSelect))
                    for k = 1:length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Resists)
                        subtype = 'R';
                        sens1 = num2str(round(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.(supSelect)(k)*1000)/1000);
                        ntype = num2str(k);
                        senStr = strcat({'<HTML><table border="1" style="width:177px"><tr><td style="width:30%;text-align:center;font-size:8px">S<sub>'}, subtype, ntype, {'</sub><sup>'}, suptype, {'</su></td><td style="width:70%;text-align:center;font-size:9px">'}, sens1, {'</td></tr></HTML>'});
                        strTotal = [strTotal; senStr];
                    end
                    for m = 1:length(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.Caps)
                        subtype = 'C';
                        sens1 = num2str(round(this.cellList{this.selectedStage, 1}{this.selectedCells(this.selectedStage)}.(supSelect)(m+k)*1000)/1000);
                        ntype = num2str(m);
                        senStr = strcat({'<HTML><table border="1" style="width:177px"><tr><td style="width:30%;text-align:center;font-size:8px">S<sub>'}, subtype, ntype, {'</sub><sup>'}, suptype, {'</su></td><td style="width:70%;text-align:center;font-size:9px">'}, sens1, {'</td></tr></HTML>'});
                        strTotal = [strTotal; senStr];
                    end
                end
            end
            set(this.handles.sensivitiesList, 'String', strTotal);
        end  
    end
end

function removeAxis(sP)
    set(sP, 'XTickLabelMode', 'Manual');
    set(sP, 'XTick', []);
    set(sP, 'YTickLabelMode', 'Manual');
    set(sP, 'YTick', []);
end